package Control;

import Model.Customer;
import Model.ShopSupport;
import Model.Transaction;
import Model.Util;
import com.oreilly.servlet.MultipartRequest;
import com.oreilly.servlet.multipart.DefaultFileRenamePolicy;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.util.Enumeration;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import sun.security.x509.X509CertImpl;

/**
 *
 * @author user
 */
public class ProcessAuthenticate extends HttpServlet {

    /** 
     * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        HttpSession session = request.getSession();
        String authenticateCode = (String)session.getAttribute("authenticatecode");
        MultipartRequest multipartRequest = null;
        String encType = "utf-8";
        String folderUpload = getServletContext().getRealPath("\\certificateupload");
//        System.out.println(folderUpload);
        int maxSize = 5 * 1024 * 1024;
        multipartRequest = new MultipartRequest(request, folderUpload, maxSize, encType, new DefaultFileRenamePolicy());
//        -------------------------------------
        int status = 1;
        String sign = multipartRequest.getParameter("sign");
        System.out.println("code authenticate" + Util.authenticateCode);
//         lay danh sach cac file trong input file
        Enumeration files = multipartRequest.getFileNames();
        //         tra va ten cua tag input file chu khong phai ten file 
        String name = (String) files.nextElement();
        //          tra ve ten file tren server sau khi upload va truyen vo doi tuong file  
        File currentFile = multipartRequest.getFile(name);
        if (currentFile==null) {
            request.setAttribute("missfile", "Quý khách chưa upload certificate");
            status = 0;
        }

        if (sign.equals("")) {
            request.setAttribute("errorsign", "Quý khách chưa kí mã xác nhận trên");
            status = 0;
        }
        if (status == 0) {
            RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/authenticate.jsp");
            dispatcher.forward(request, response);
            return;
        }


        String fileName = currentFile.getName();
        String extension = fileName.substring(fileName.length() - 3, fileName.length());
        System.out.println("Extension of file " +extension);
        if (!extension.equals("cer")) {
            request.setAttribute("errorfile", "File quý khách upload không phải là certificate");
            status = -1;
        }
        if (status == -1) {
            currentFile.delete();
            RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/authenticate.jsp");
            dispatcher.forward(request, response);
            return;
        }

//   -------------------------------------    
//      
//        tra ve content type cua file theo chuan mime xem tai http://en.wikipedia.org/wiki/Internet_media_type
        String type = multipartRequest.getContentType(name);
//        tra ve ten file goc tren may client
        String originalFilename = multipartRequest.getOriginalFileName(name);
//    
//        ---------------------------------------



        if (status == 1) {
            try {
                X509CertImpl cerimplement = new X509CertImpl(new FileInputStream(currentFile));
                BASE64Encoder encoder = new BASE64Encoder();
                String cerEncode = encoder.encode(cerimplement.getEncoded());
                String result = authenticate(cerEncode);
                if (result.equals("valid")) {
                    PublicKey pub = cerimplement.getPublicKey();
                    System.out.println("valid");
                    try {
                        boolean verified = verifySign(authenticateCode, sign, pub);
                        if(verified){
                            System.out.println("Verifi successful");
                            ShopSupport shop = (ShopSupport) session.getAttribute("shop");
                            if(shop==null){
                            Transaction transfer = (Transaction) session.getAttribute("transaction");
                            Customer.transfer(transfer.getFromAccount(),transfer.getToAccount(), transfer.getAmount(), transfer.getContent());
                            response.sendRedirect("transfersuccess.jsp");
                            }
                            else{
                                Customer customer = (Customer) session.getAttribute("sessionlogin");
                                Customer.transfer(customer.getAccountid(), shop.getToAccount(), shop.getAmount(), "Thanh toán shop online");
                                session.removeAttribute("shop");
                                session.removeAttribute("loginbank");
                                response.sendRedirect(shop.getSite());
                            }
                        }
                        else{
                            currentFile.delete();
                            response.sendRedirect("transferfail.jsp");
                        }
                    } catch (Exception ex) {
                        Logger.getLogger(ProcessAuthenticate.class.getName()).log(Level.SEVERE, null, ex);
                    } 
                }
                if (result.equals("invalid")) {
                    System.out.println("invalid");
                    response.sendRedirect("transferfail.jsp");
                }
            } catch (CertificateException ex) {
                Logger.getLogger(ProcessAuthenticate.class.getName()).log(Level.SEVERE, null, ex);
            }

        }

//        response.sendRedirect("transfersuccess.jsp");
    }

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /** 
     * Handles the HTTP <code>GET</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /** 
     * Handles the HTTP <code>POST</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /** 
     * Returns a short description of the servlet.
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>

    private static String authenticate(java.lang.String certEncoded) {
        ca.AuthenServiceService service = new ca.AuthenServiceService();
        ca.AuthenService port = service.getAuthenServicePort();
        return port.authenticate(certEncoded);
    }

    private static boolean verifySign(String originalMessage, String signMessage, PublicKey publicKey) throws IOException, SignatureException, NoSuchAlgorithmException, InvalidKeyException {
        BASE64Decoder decoder = new BASE64Decoder();
        byte[] signByte = decoder.decodeBuffer(signMessage);
        byte[] originalByte = originalMessage.getBytes("UTF-8");
        Signature signature = Signature.getInstance("MD5WithRSA");
        signature.initVerify(publicKey);
        signature.update(originalByte);
        boolean verified = signature.verify(signByte);
        return verified;

    }
}